
// Author: Sergio Castaño Arteaga
// Email: sergio.castano.arteaga@gmail.com

// ***************************************************************************
// General
// ***************************************************************************

var conf = require("./config")
var mongoose = require('mongoose');
// External dependencies
var express = require('express'),
    http = require('http'),
    events = require('events'),
    _ = require('underscore'),
    request = require("request"),
    sanitize = require('validator').sanitize;


// HTTP Server configuration & launch
var app = express(),
    server = http.createServer(app);
    server.listen(conf.port);

mongoose.connect('mongodb://localhost/meanchat');
var Message = require('./model/message');

// Express app configuration
app.configure(function() {
    app.use(express.bodyParser());
    app.use(express.static(__dirname + '/static'));
});

var io = require('socket.io')(server);


var _predb = require('redis').createClient;
var db = _predb(conf.dbPort,conf.dbHost,conf.dbOptions);
var redis = require('socket.io-redis');
// var adapter = require('socket.io-redis');
var pub = _predb(conf.dbPort, conf.dbHost, conf.dbOptions);
var sub = _predb(conf.dbPort, conf.dbHost, conf.dbOptions);

io.adapter(redis({ pubClient: pub, subClient: sub }));


// Logger configuration
var logger = new events.EventEmitter();
logger.on('newEvent', function(event, data) {
    // Console log
    console.log('-----  %s: %s', event, JSON.stringify(data));
    // Persistent log storage too?
    // TODO
});

// ***************************************************************************
// Express routes helpers
// ***************************************************************************

// Only authenticated users should be able to use protected methods
var requireAuthentication = function(req, res, next) {
    // TODO
    next();
};

// Sanitize message to avoid security problems
var sanitizeMessage = function(req, res, next) {
    if (req.body.msg) {
        req.sanitizedMessage = sanitize(req.body.msg).xss();
        next();
    } else {
        res.send(400, "No message provided");
    }
};

// Send a message to all active rooms
var sendBroadcast = function(text) {
    _.each(io.nsps['/'].adapter.rooms, function(room) {
        if (room) {
            var message = {'room':room, 'username':'ServerBot', 'msg':text, 'date':new Date()};
            io.to(room).emit('newMessage', message);
        }
    });
    logger.emit('newEvent', 'newBroadcastMessage', {'msg':text});
};

// ***************************************************************************
// Express routes
// ***************************************************************************

// Welcome message
app.use(express.static(__dirname + '/static'));


app.get("/",function(req,res){
  res.status(200).sendfile(__dirname + '/static/index.html');
})

app.get("/chat",function(req,res){
  //此时，最好http与io保持session一致
  if(!req.query['from.name']){
    res.redirect(conf.authPage);
  }else{
    res.status(200).sendfile(__dirname + '/static/index.html');
  }
})

app.get('/getAllRecMsg',function(req,res){
  var openid = req.query['openid']
  UserRelation.find({userid : openid, isblind : false},function(err0,urs){
    if (err0) res.json({err:err0})
    var alltouserid = _.pluck(allIdsInDb, 'toopenid')

    Message.aggregate([
      {
          $match: {'$or':[{'userid': openid},{'fromuserid': openid}],$nin : alltouserid }
      },
      {
        $group: {
          _id: { 
            fromuserid: '$fromuserid',
            fromusername: '$fromUsername',
            username: '$username',
            userid : '$userid',
          },
          lasttime: {$max : "$createTime" }
        } 
      }
      ])
    .limit(50)
    .sort('lasttime')
    .exec(function(err,msgs){
      var result = {};
      var toopenids = []
      _.each(msgs,function(m){
        var toopenid = m._id.fromuserid == openid? m._id.userid : m._id.fromuserid
        if(result[toopenid]){
          if (result[toopenid].lasttime < m.lasttime)
            result[toopenid] = m
        }else{
          result[toopenid] = m
        }
      })

      res.json(_.values(result));
    })
  })



})
app.get('/getLastMsg',function(req,res){
  var fromopenid = req.query['from.from_openid']
  var toopenid = req.query['to.openid']

  Message.find({"$or": [{
    userid : toopenid,
    fromuserid : fromopenid
  },{
    userid : fromopenid,
    fromuserid : toopenid
  }]})
  .limit(50)
  .sort('-createTime')
  .exec(function(err,msgs){
    if (!!err ) res.json(err)
    res.json(msgs)
  })

})


// ***************************************************************************
// Socket.io events
// ***************************************************************************

io.sockets.on('connection', function(socket) {

    // Welcome message on connection
    socket.emit('connected', 'Welcome to the chat server');
    logger.emit('newEvent', 'userConnected', {'socket':socket.id});

    // Store user data in db
    db.hset([socket.id, 'connectionDate', new Date()], redis.print);
    db.hset([socket.id, 'socketId', socket.id], redis.print);
    // db.hset([socket.id, 'username', 'anonymous'], redis.print);

    // 新上来就马上加入主server的大room，大广场

    //socket.join(conf.mainroom);
    //logger.emit('newEvent', 'userJoinsRoom', {'socket':socket.id, 'room':conf.mainroom});
    // 通知前端，你已经加入了主server，这句其实不发也行，用户即使得到这个消息也没什么作为
    //socket.emit('subscriptionConfirmed', {'room':conf.mainroom});
    // Notify subscription to all users in room
    //var data = {'room':conf.mainroom, 'username':'anonymous', 'msg':'----- Joined the room -----', 'id':socket.id};
    //io.to(conf.mainroom).emit('userJoinsRoom', data);


    socket.on("blindUser",function(data){
      UserRelation.findOne({userid : data.openid,toopenid : data.toopenid},function(err,ur){
        if (err){
          var rela = new UserRelation({
            userid : data.openid,
            toopenid : data.toopenid,
            isblind : data.isblind
          })
          rela.save()
        }else{
          ur.set({isblind: data.isblind})
          ur.save();
        }
      })
    })
    


    // User wants to know what rooms he has joined
    socket.on('getUnread', function(data) {
        //room信息不这么拿，要从数据库里面拿
        db.hgetall(socket.id, function(err, obj) {
          if (err) return logger.emit('newEvent', 'error', err);
          var userid = obj.openid
          Message.find({'userid': userid, isRead: false},function(err,msgs){
            if (err) return logger.emit('newEvent', 'error', err);
            //console.log(msgs)
            if (msgs && msgs.length >0){
              var msg2 = _.map(msgs,function(m){
                  return {openid: m.fromuserid, name: m.fromUsername,content: m.content,createTime: m.createTime}
              })
              socket.emit('unreadmsgs',msg2)
              //送达完了，更改原有状态
              Message.update({'userid': userid, isRead: false},{$set:{isRead:true}},{ multi: true },function(err){});
            }else{
              socket.emit('unreadmsgs',[])
            }
          })

        })

        logger.emit('newEvent', 'getUnread', {'socket':socket.id});
    });

    // Get users in given room
    socket.on('getUsersInRoom', function(data) {
        var usersInRoom = [];
        var socketsInRoom = _.keys(io.nsps['/'].adapter.rooms[data.room]);
        for (var i=0; i<socketsInRoom.length; i++) {
            db.hgetall(socketsInRoom[i], function(err, obj) {
                usersInRoom.push({'room':data.room, 'username':obj.username, 'id':obj.socketID});
                // When we've finished with the last one, notify user
                if (usersInRoom.length == socketsInRoom.length) {
                    socket.emit('usersInRoom', {'users':usersInRoom});
                }
            });
        }
    });

    // User wants to change his nickname
    socket.on('setConvensation', function(data) {
        // Store user data in db
        var from = data.from, to = data.to;
        console.log('---setConvensation---');
        console.log(data);
        db.hset([socket.id, 'openid', from.openid], redis.print);
        db.hset([socket.id, 'username', from.name], redis.print);
        // 存放user信息，user信息可能
        db.hset([from.openid, 'connectionDate', new Date()], redis.print);
        db.hset([from.openid, 'username',from.name], redis.print);
        db.hset([from.openid, 'socketId', socket.id], redis.print);
        if (!!to){
          db.hset([to.openid, 'connectionDate', new Date()], redis.print);
          db.hset([to.openid, 'username',to.name], redis.print);
          //db.hset([to.openid, 'socketId', socket.id], redis.print);
        }
    });

    // New message sent to special one
    socket.on('newMessage', function(data) {
      var openid = data.to, content = data.content;

      db.hgetall(socket.id, function(err, me) {
        db.hgetall(openid,function(err,obj){
          if (err) console.log('find target person err' + err)
          var targetonline = false
          if (obj.socketId && obj.socketId !==''){
            socket.broadcast.to(obj.socketId).emit('newMessage',{
              openid: me.openid, name: me.username,content: content
            })
            targetonline = true
          }else{
            request.post(conf.mainhost, {form:{from_openid: me.openid, to_openid: openid}},
              function optionalCallback(err, httpResponse, body) {
              if (err) {
                return console.error('upload failed:', err);
              }
              console.log('Upload successful!  Server responded with:', body);
            })
          }
          //如果不在线，发送模板消息给对方
          //save msg to db
          var msg = new Message({
            userid : openid,
            username: obj.username,
            fromuserid : me.openid,
            fromUsername : me.username,
            createTime: new Date(),
            content : content,
            isRead : targetonline
          })
          msg.save(function(err){
            err && console.log(err)
            //console.log("save msg ok");
            //Message.find({},function(err,data){
              //console.log(data)
            //})

          })
        })
      })
    });

    // Clean up on disconnect
    socket.on('disconnect', function() {

        // Get current rooms of user
        var rooms = socket.rooms;

        // Get user info from db
        db.hgetall(socket.id, function(err, obj) {

            if (err) return logger.emit('newEvent', 'error', err);
            logger.emit('newEvent', 'userDisconnected', {'socket':socket.id});
            logger.emit('newEvent', 'userDisconnected-data', obj);
            if (!!obj && obj.openid)
              db.hset([obj.openid, 'socketId', ''], redis.print); //清除socketid
        });

        // Delete user from db
        db.del(socket.id, redis.print);
    });
});
var makeroom =function(user1,user2){
  return user1 > user2 ?  user1 + "_" + user2 : user2 + "_" + user1
}
// Automatic message generation (for testing purposes)
if (conf.debug) {
    setInterval(function() {
        var text = 'Testing rooms';
        sendBroadcast(text);
    }, 60000);
}
